package com.luowei.media;

import java.util.ArrayList;

import javax.microedition.khronos.opengles.GL11;

import com.luowei.media.R;

import android.graphics.Typeface;
import android.view.MotionEvent;

public final class PathBarLayer extends Layer {
    private static final StringTexture.Config sPathFormat = new StringTexture.Config();
    private final ArrayList<Component> mComponents = new ArrayList<Component>();
    private static final int FILL = R.drawable.pathbar_bg;
    private static final int JOIN = R.drawable.pathbar_join;
    private static final int CAP = R.drawable.pathbar_cap;
    private Component mTouchItem = null;

    static {
        sPathFormat.fontSize = 18f * Gallery.PIXEL_DENSITY;
    }

    public PathBarLayer() {
    }

    public void pushLabel(int icon, String label, Runnable action) {
        mComponents.add(new Component(icon, label, action, 0));
        recomputeComponents();
    }

    public void setAnimatedIcons(final int[] icons) {
        final int numComponents = mComponents.size();
        for (int i = 0; i < numComponents; ++i) {
            final Component component = mComponents.get(i);
            if (component != null) {
                if (component.animatedIcons != null) {
                    component.animatedIcons = null;
                }
                if (i == numComponents - 1) {
                    component.animatedIcons = icons;
                }
            }
        }
    }

    public void changeLabel(String label) {
        if (label == null || label.length() == 0)
            return;
        Component component = popLabel();
        if (component != null) {
            pushLabel(component.icon, label, component.action);
        }
    }

    public String getCurrentLabel() {
        final ArrayList<Component> components = mComponents;
        int lastIndex = components.size() - 1;
        if (lastIndex < 0) {
            return "";
        }
        Component retVal = components.get(lastIndex);
        return retVal.origString;
    }

    public Component popLabel() {
        final ArrayList<Component> components = mComponents;
        int lastIndex = components.size() - 1;
        if (lastIndex < 0) {
            return null;
        }
        Component retVal = components.get(lastIndex);
        components.remove(lastIndex);
        return retVal;
    }

    private static final class Component {
        public String origString;
        public int icon;
        public Runnable action;
        public StringTexture texture;
        public float width;
        public float animWidth;
        public float x;
        public int[] animatedIcons;
        public float timeElapsed;
        private static final float ICON_WIDTH = 38.0f;

        Component(int icon, String label, Runnable action, float widthLeft) {
            this.action = action;
            origString = label;
            this.icon = icon;
            computeLabel(widthLeft);
        }

        public final void computeLabel(float widthLeft) {
            Typeface typeface = sPathFormat.bold ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT;
            String label = "";
            if (origString != null) {
                label = origString.substring(0, StringTexture.lengthToFit(sPathFormat.fontSize, widthLeft, typeface, origString));
                if (label.length() != origString.length()) {
                    label += "...";
                }
            }
            this.texture = new StringTexture(label, sPathFormat);
        }

        public final boolean update(float timeElapsed) {
            this.timeElapsed += timeElapsed;
            if (animWidth == 0.0f) {
                animWidth = width;
            }
            animWidth = FloatUtils.animate(animWidth, width, timeElapsed);
            if (animatedIcons != null && animatedIcons.length > 1)
                return true;
            if (animWidth == width) {
                return false;
            } else {
                return true;
            }
        }

        public float getIconWidth() {
            return ICON_WIDTH * Gallery.PIXEL_DENSITY;
        }
    }

    @Override
    public void generate(RenderView view, RenderView.Lists lists) {
        lists.blendedList.add(this);
        lists.hitTestList.add(this);
        lists.updateList.add(this);
    }

    private void layout() {
        int numComponents = mComponents.size();
        for (int i = 0; i < numComponents; ++i) {
            Component component = mComponents.get(i);
            float iconWidth = (component.icon == 0) ? 0 : component.getIconWidth();
            if (iconWidth == 0) {
                iconWidth = 8 * Gallery.PIXEL_DENSITY;
            }
            float offset = 5 * Gallery.PIXEL_DENSITY;
            float thisComponentWidth = (i != numComponents - 1) ? iconWidth + offset : component.texture.computeTextWidth()
                    + iconWidth + offset;
            component.width = thisComponentWidth;
        }
    }

    @Override
    public boolean update(RenderView view, float timeElapsed) {
        layout();
        boolean retVal = false;
        int numComponents = mComponents.size();
        for (int i = 0; i < numComponents; i++) {
            Component component = mComponents.get(i);
            retVal |= component.update(timeElapsed);
        }
        return retVal;
    }

    @Override
    public void renderBlended(RenderView view, GL11 gl) {
        // Draw components.
        final Texture fill = view.getResource(FILL);
        final Texture join = view.getResource(JOIN);
        final Texture cap = view.getResource(CAP);
        final float y = mY + 3;
        int x = (int) (3 * Gallery.PIXEL_DENSITY);
        float height = mHeight;
        int numComponents = mComponents.size();
        for (int i = 0; i < numComponents; ++i) {
            Component component = mComponents.get(i);
            component.x = x;
            // Draw the left join if not the first component, and the fill.
            // TODO: Draw the pressed background for mTouchItem.
            final int width = (int) component.animWidth;
            if (i != 0) {
                view.draw2D(join, x - join.getWidth(), y);
                if (view.bind(fill)) {
                    view.draw2D(x, y, 0f, width, height);
                }
            } else if (view.bind(fill)) {
                view.draw2D(0f, y, 0f, x + width, height);
            }

            if (i == numComponents - 1) {
                // Draw the cap on the right edge.
                view.draw2D(cap, x + width, y);
            }
            float xOffset = 5 * Gallery.PIXEL_DENSITY;
            // Draw the label.
            final int[] icons = component.animatedIcons;

            // Cycles animated icons.
            final int iconId = (icons != null && icons.length > 0) ? icons[(int) (component.timeElapsed * 20.0f) % icons.length]
                    : component.icon;
            final Texture icon = view.getResource(iconId);
            if (icon != null) {
                view.loadTexture(icon);
                view.draw2D(icon, x + xOffset, y - 2 * Gallery.PIXEL_DENSITY);
            }
            if (i == numComponents - 1) {
                final StringTexture texture = component.texture;
                view.loadTexture(texture);
                float iconWidth = component.getIconWidth();
                if (texture.computeTextWidth() <= (width - iconWidth)) {
                    float textOffset = (iconWidth == 0) ? 8 * Gallery.PIXEL_DENSITY : iconWidth;
                    view.draw2D(texture, x + textOffset, y + 5);
                }
            }
            x += (int) (width + (21 * Gallery.PIXEL_DENSITY + 0.5f));
        }
    }

    private Component hitTestItems(float x, float y) {
        if (y >= mY && y < mY + mHeight) {
            int numComponents = mComponents.size();
            for (int i = 0; i < numComponents; i++) {
                final Component component = mComponents.get(i);
                float componentx = component.x;
                if (x >= componentx && x < componentx + component.width) {
                    return component;
                }
            }
        }
        return null;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final float x = event.getX();
        final float y = event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mTouchItem = hitTestItems(x, y);
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_UP:
            if (mTouchItem != null) {
                mTouchItem.action.run();
            }
        case MotionEvent.ACTION_CANCEL:
            mTouchItem = null;
            break;
        }
        return true;
    }

    public void recomputeComponents() {
        float width = mWidth;
        width -= 20f * Gallery.PIXEL_DENSITY;
        int numComponents = mComponents.size();
        for (int i = 0; i < numComponents; i++) {
            Component component = mComponents.get(i);
            width -= (component.getIconWidth() + 20.0f * Gallery.PIXEL_DENSITY);
            component.computeLabel(width);
        }
    }

    public int getNumLevels() {
        return mComponents.size();
    }

    public void clear() {
        mComponents.clear();
    }
}
